// Contient toutes les spécifications de classes nécessaires
// pour représenter l'arbre abstrait
#ifndef ARBRE_H_
#define ARBRE_H_
#include <vector>
#include <iostream>
#include <iomanip>
using namespace std;


#include "Symbole.h"
////////////////////////////////////////////////////////////////////////////////

class Noeud {
// classe abstraite dont dériveront toutes les classes servant à représenter l'arbre abstrait
// Remarque : la classe ne contient aucun constructeur
  public:  
    virtual int  getValeur() =0 ;  
    virtual void afficher(unsigned short indentation=0) { cout << setw(4*indentation) << " "; }
    virtual ~Noeud() {}
};

////////////////////////////////////////////////////////////////////////////////
class NoeudSeqInst : public Noeud {
// classe pour représenter un noeud "sequence d'instruction"
// qui a autant de fils que d'instructions dans la séquence
  public:
     NoeudSeqInst();   // construit une séquence d'instruction vide
    ~NoeudSeqInst() {} // à cause du destructeur virtuel de la classe Noeud
    int getValeur(); // évalue chaque instruction de la séquence
    void afficher(unsigned short indentation=0); // affiche la séquence d'instructions
    void ajouteInstruction(Noeud* instruction);  // ajoute une instruction à la séquence

  private:
    vector<Noeud *> tabInst; // pour stocker les instructions de la séquence
};

////////////////////////////////////////////////////////////////////////////////
class NoeudAffectation : public Noeud {
// classe pour représenter un noeud "affectation"
// composé de 2 fils : la variable et l'expression qu'on lui affecte
  public:
     NoeudAffectation(Noeud* variable, Noeud* expression); // construit une affectation
    ~NoeudAffectation() {} // à cause du destructeur virtuel de la classe Noeud
    int getValeur(); // évalue l'expression et affecte sa valeur à la variable
    void afficher(unsigned short indentation=0); // affiche l'affectation

  private:
    Noeud* variable;
    Noeud* expression;
};

////////////////////////////////////////////////////////////////////////////////
class NoeudOperateurUnitaire : public Noeud{
  public:
    NoeudOperateurUnitaire(Symbole operateur, Noeud* operandeDroit);
   ~NoeudOperateurUnitaire() {}
    int getValeur();
    void afficher(unsigned short indentation=0);
protected:
    Symbole operateur;
    Noeud*  operandeDroit;
};
////////////////////////////////////////////////////////////////////////////////
class NoeudOperateurBinaire : public NoeudOperateurUnitaire {
// classe pour représenter un noeud "opération arithmétique" composé d'un opérateur (+-*/)
// et de 2 fils : l'opérande gauche et l'opérande droit
  public:
    NoeudOperateurBinaire(Symbole operateur, Noeud* operandeGauche, Noeud* operandeDroit);
     // construit une opération binaire : operandeGauche operateur OperandeDroit
   ~NoeudOperateurBinaire() {} // à cause du destructeur virtuel de la classe Noeud
    int getValeur(); // évalue l'operande gauche, l'operande droit et applique l'opérateur
    void afficher(unsigned short indentation=0); // affiche l'opération
  private:
    Noeud*  operandeGauche;
};

class NoeudStructureControl : public Noeud{
public:
    NoeudStructureControl(string nom="iterative");
    ~NoeudStructureControl(){}
    int getValeur();
    void afficher(unsigned short indentation=0);
    void ajouteCondition(Noeud* condition);
    void ajouteSeqInt(Noeud*seqInst);
protected:
    Noeud* condition,* seqInst;
    string nom;
};

class NoeudSi : public NoeudStructureControl{
public:
    NoeudSi(Noeud* conditionPrincipal, Noeud* seqInstPrincipal);
    ~NoeudSi(){}
    int getValeur();
    void afficher(unsigned short indentation=0);
    void ajouteSinonsiCondition(Noeud* sinonsiCondition);
    void ajouteSinonsiSeqInst(Noeud* sinonsiSeqInst);
    void ajouteSinon(Noeud* sinon);
private:
    vector<Noeud*> sinonsiCondition,sinonsiSeqInst;
    Noeud* sinon;
    bool bSinon;
};

class NoeudFaireJusqua : public NoeudStructureControl{
public:
    NoeudFaireJusqua();
    ~NoeudFaireJusqua(){}
    int getValeur();    
};

class NoeudPour : public NoeudStructureControl{
public:
    NoeudPour();
    ~NoeudPour(){}
    int getValeur();
    void afficher(unsigned short indentation=0);
    void ajouteInitialization(Noeud* initialization);
    void ajouteModificateur(Noeud* modificateur);
private:
    vector<Noeud*> initialization,modificateur;
};

class NoeudLire : public Noeud{
public:
    NoeudLire(Noeud* variable);
    ~NoeudLire(){}
    int getValeur();
    void afficher(unsigned short indentation=0);
private:
    Noeud* variable;
};

class NoeudEcrire : public Noeud{
public:
    NoeudEcrire(Noeud* sortie);
    ~NoeudEcrire(){}
    int getValeur();
    void afficher(unsigned short indentation=0);
private:
    Noeud* sortie;
};


#endif 